package log

import (
	"bytes"
	"context"
	"io"
	"os"
	"sync"
	"sync/atomic"
	"time"

	"gitee.com/doraemon1996/bunny/structure"
)

// 日志对象
type Logger struct {
	// 日志数据输出对象
	// 通常是`os.Stdout`,也可以指定为其它适合的对象
	Output io.Writer

	// 钩子函数
	// 通常用于捕获指定日志等级的日志数据
	Hooks LevelHooks

	// 日志数据格式化对象
	// 所有日志数据都将使用该对象格式化
	Formatter Formatter

	// 是否在日志数据中添加调用位置的标志
	ReportCaller bool

	// 需要记录的日志等级
	Level Level

	// 读写锁
	// 用于保证日志顺序,以及共享变量读写
	mutex sync.RWMutex

	// Entry复用池
	entryPool sync.Pool

	// 日志数据异步处理对象
	writer *writer
}

// 创建一个新的日志对象
// 该日志对象会启动一个工作协程,处理将日志数据写入到输出对象的任务
// 当日志对象使用完毕后,应当调用Close()函数,退出关闭协程
func New() *Logger {

	logger := &Logger{
		Output:       os.Stdout,
		Formatter:    new(TextFormatter),
		Hooks:        make(LevelHooks),
		Level:        Level_Info,
		ReportCaller: false,
	}

	logger.writer = &writer{
		ctl:    new(structure.Control),
		logger: logger,
		pipe:   make(chan *bytes.Buffer, 10000),
	}
	logger.writer.ctl.Init(context.Background(), nil)
	logger.writer.Start()

	return logger
}

func (logger *Logger) newEntry() *Entry {
	entry, ok := logger.entryPool.Get().(*Entry)
	if ok {
		return entry
	}

	return NewEntry(logger)
}

func (logger *Logger) releaseEntry(entry *Entry) {
	entry.Data = make(Fields)
	logger.entryPool.Put(entry)
}

func (logger *Logger) GetLevel() Level {
	return Level(atomic.LoadUint32((*uint32)(&logger.Level)))
}

// 判断当前日志等级是否大于指定等级
func (logger *Logger) IsLevelEnabled(level Level) bool {
	return logger.GetLevel() >= level
}

// 返回一个新的日志条目结构,并将键值对添加进去
func (logger *Logger) WithField(key string, value any) *Entry {
	entry := logger.newEntry()
	defer logger.releaseEntry(entry)
	return entry.WithField(key, value)
}

// 返回一个新的日志条目结构,并将键值对列表添加进去
func (logger *Logger) WithFields(fields Fields) *Entry {
	entry := logger.newEntry()
	defer logger.releaseEntry(entry)
	return entry.WithFields(fields)
}

// 返回一个新的日志条目结构,并指定日志时间
func (logger *Logger) WithTime(t time.Time) *Entry {
	entry := logger.newEntry()
	defer logger.releaseEntry(entry)
	return entry.WithTime(t)
}

// 返回一个新的日志条目结构,并指定上下文Context
func (logger *Logger) WithContext(ctx context.Context) *Entry {
	entry := logger.newEntry()
	defer logger.releaseEntry(entry)
	return entry.WithContext(ctx)
}

// 返回一个新的日志条目结构,并指定错误信息
func (logger *Logger) WithError(err error) *Entry {
	entry := logger.newEntry()
	defer logger.releaseEntry(entry)
	return entry.WithError(err)
}

func (logger *Logger) Log(level Level, args ...any) {
	if logger.IsLevelEnabled(level) {
		entry := logger.newEntry()
		entry.Log(level, args...)
		logger.releaseEntry(entry)
	}
}

func (logger *Logger) Trace(args ...any) {
	logger.Log(Level_Trace, args...)
}

func (logger *Logger) Debug(args ...any) {
	logger.Log(Level_Debug, args...)
}

func (logger *Logger) Print(args ...any) {
	logger.Log(Level_Info, args...)
}

func (logger *Logger) Info(args ...any) {
	logger.Log(Level_Info, args...)
}

func (logger *Logger) Warn(args ...any) {
	logger.Log(Level_Warn, args...)
}

func (logger *Logger) Warning(args ...any) {
	logger.Log(Level_Warn, args...)
}

func (logger *Logger) Error(args ...any) {
	logger.Log(Level_Error, args...)
}

func (logger *Logger) Fatal(args ...any) {
	logger.Log(Level_Fatal, args...)
	Exit(1)
}

func (logger *Logger) Panic(args ...any) {
	logger.Log(Level_Panic, args...)
}

func (logger *Logger) Logf(level Level, format string, args ...any) {
	if logger.IsLevelEnabled(level) {
		entry := logger.newEntry()
		entry.Logf(level, format, args...)
		logger.releaseEntry(entry)
	}
}

func (logger *Logger) Tracef(format string, args ...any) {
	logger.Logf(Level_Trace, format, args...)
}

func (logger *Logger) Debugf(format string, args ...any) {
	logger.Logf(Level_Debug, format, args...)
}

func (logger *Logger) Printf(format string, args ...any) {
	logger.Logf(Level_Info, format, args...)
}

func (logger *Logger) Infof(format string, args ...any) {
	logger.Logf(Level_Info, format, args...)
}

func (logger *Logger) Warnf(format string, args ...any) {
	logger.Logf(Level_Warn, format, args...)
}

func (logger *Logger) Warningf(format string, args ...any) {
	logger.Logf(Level_Warn, format, args...)
}

func (logger *Logger) Errorf(format string, args ...any) {
	logger.Logf(Level_Error, format, args...)
}

func (logger *Logger) Fatalf(format string, args ...any) {
	logger.Logf(Level_Fatal, format, args...)
	Exit(1)
}

func (logger *Logger) Panicf(format string, args ...any) {
	logger.Logf(Level_Panic, format, args...)
}

func (logger *Logger) Logln(level Level, args ...any) {
	if logger.IsLevelEnabled(level) {
		entry := logger.newEntry()
		entry.Logln(level, args...)
		logger.releaseEntry(entry)
	}
}

func (logger *Logger) Traceln(args ...any) {
	logger.Logln(Level_Trace, args...)
}

func (logger *Logger) Debugln(args ...any) {
	logger.Logln(Level_Debug, args...)
}

func (logger *Logger) Println(args ...any) {
	logger.Logln(Level_Info, args...)
}

func (logger *Logger) Infoln(args ...any) {
	logger.Logln(Level_Info, args...)
}

func (logger *Logger) Warnln(args ...any) {
	logger.Logln(Level_Warn, args...)
}

func (logger *Logger) Warningln(args ...any) {
	logger.Logln(Level_Warn, args...)
}

func (logger *Logger) Errorln(args ...any) {
	logger.Logln(Level_Error, args...)
}

func (logger *Logger) Fatalln(args ...any) {
	logger.Logln(Level_Fatal, args...)
	Exit(1)
}

func (logger *Logger) Panicln(args ...any) {
	logger.Logln(Level_Panic, args...)
}

func (logger *Logger) LogFn(level Level, f FunctionLog) {
	if logger.IsLevelEnabled(level) {
		entry := logger.newEntry()
		entry.Log(level, f()...)
		logger.releaseEntry(entry)
	}
}

func (logger *Logger) TraceFn(f FunctionLog) {
	logger.LogFn(Level_Trace, f)
}

func (logger *Logger) DebugFn(f FunctionLog) {
	logger.LogFn(Level_Debug, f)
}

func (logger *Logger) PrintFn(f FunctionLog) {
	logger.LogFn(Level_Info, f)
}

func (logger *Logger) InfoFn(f FunctionLog) {
	logger.LogFn(Level_Info, f)
}

func (logger *Logger) WarnFn(f FunctionLog) {
	logger.LogFn(Level_Warn, f)
}

func (logger *Logger) WarningFn(f FunctionLog) {
	logger.LogFn(Level_Warn, f)
}

func (logger *Logger) ErrorFn(f FunctionLog) {
	logger.LogFn(Level_Error, f)
}

func (logger *Logger) FatalFn(f FunctionLog) {
	logger.LogFn(Level_Fatal, f)
	Exit(1)
}

func (logger *Logger) PanicFn(f FunctionLog) {
	logger.LogFn(Level_Panic, f)
}

// 动态设置日志等级
func (logger *Logger) SetLevel(level Level) {
	atomic.StoreUint32((*uint32)(&logger.Level), uint32(level))
}

// 动态设置日志数据序列化对象
func (logger *Logger) SetFormatter(formatter Formatter) {
	logger.mutex.Lock()
	defer logger.mutex.Unlock()

	logger.Formatter = formatter
}

// 动态设置日志数据输出对象
func (logger *Logger) SetOutput(output io.Writer) {
	logger.mutex.Lock()
	defer logger.mutex.Unlock()

	logger.Output = output
}

// 动态设置日志调用位置记录标识
func (logger *Logger) SetReportCaller(reportCaller bool) {
	logger.mutex.Lock()
	defer logger.mutex.Unlock()

	logger.ReportCaller = reportCaller
}

// 动态添加钩子函数
func (logger *Logger) AddHook(hook Hook) {
	logger.mutex.Lock()
	defer logger.mutex.Unlock()

	logger.Hooks.Add(hook)
}

// 动态覆盖钩子函数列表
func (logger *Logger) ReplaceHooks(hooks LevelHooks) LevelHooks {
	logger.mutex.Lock()
	old := logger.Hooks
	logger.Hooks = hooks
	logger.mutex.Unlock()

	return old
}

// 关闭工作协程
func (logger *Logger) Stop() {
	logger.writer.Stop()
}
